using System;
using System.Collections;
using System.Data;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.CDS;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.Humans
{
    /// <summary>
    /// Page for adding external people (those without a Partners username) as study staff 
    /// on a study.  The page presents the user with a question, asking whether the user has 
    /// any external people to staff to the study.  If the user selects "Yes", the user is
    /// presented with a form to fill out describing the new person.  After the user saves
    /// this information, the user is presented with another question, asking if there are
    /// more external people to staff.  If the user selects "Yes", the user is brought back
    /// to a the form, with the values removed from the previous iteration.  This process
    /// continues, until the user selects "No".  At this point, the new people are staffed
    /// to the study.
    /// 
    /// Currently, people are only staffed in the context of a process (not a protocol)
    /// </summary>
    public partial class AddExternal : BasePage
    {
        #region Instance Variables (Private)

        private ICachePolicy applicationCachePolicy;
        private ICachePolicy cachePolicy;
        private ArrayList externalStaff;
        private Hashtable pageCache;
        private ICachePolicy pageCachePolicy;
        private ProtocolProcess process;
        private Protocol protocol;
        private int protocolId;
        private int protocolProcessId;
        //This flag is used to decide whether or not the headers should be displayed
        //If the page is to be displayed as a popup, then the header section is made invisible
        private bool showAsPopUp;
        private ArrayList staffPersons;
        private ArrayList states;

        #endregion

        #region Constants

        private const string AnnunciatorTitle = "The following error(s) occurred...";
        private const string DegreeIDColumn = "Id";
        private const string DegreesKey = "DegreesKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string DegreesNameColumn = "Name";
        private const string ExternalStaffKey = "ExternalStaffKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string PageCacheKey = "AddExternalPageKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string ProcessKey = "ProcessKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string RefCodeCodeColumn = "Code";
        private const string RefCodeMeaningColumn = "Meaning";
        private const string StaffPersonsListKey = "StaffPersonsKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string StatesKey = "StatesKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";

        #endregion

        #region Properties (Private)

        /// <summary>
        /// Gets the protocol for which an external person is being added.  If it's not already
        /// in the cache, it loads it up based on the protocolId passed to the page, and caches the object
        /// </summary>
        private Protocol Protocol
        {
            get
            {
                string cacheKey = Protocol.ProtocolKey;
                protocol = cachePolicy.GetCachedObject(cacheKey) as Protocol;

                if ((protocol == null) || (protocolId != protocol.Id))
                {
                    protocol = new Protocol(cachePolicy);
                    protocol.Load(DataAccess.GetConnectionString(), protocolId);
                    cachePolicy.Cache(cacheKey, protocol);
                }
                return protocol;
            }
        }

        /// <summary>
        /// Gets the protocol process for which an external person is being added.  If it's not already
        /// in the cache, it loads it up based on the protocolProcessId passed to the page, and caches the 
        /// object
        /// </summary>
        private ProtocolProcess ProtocolProcess
        {
            get
            {
                process = cachePolicy.GetCachedObject(ProtocolProcess.ProtocolProcessKey)
                    as ProtocolProcess;

                if ((process == null) || (protocolProcessId != process.Id))
                {
                    if (protocolProcessId > 0)
                    {
                        process = ProtocolProcess.GetProtocolProcess(
                            DataAccess.GetConnectionString(), protocolProcessId, cachePolicy, null);
                        cachePolicy.Cache(ProtocolProcess.ProtocolProcessKey, process);
                    }
                    else
                    {
                        process = null;
                    }
                }
                return process;
            }
        }

        /// <summary>
        /// Gets/Sets the list of StaffPerson AdmPersonIds generated from the previous screen
        /// </summary>
        private ArrayList StaffPersons
        {
            get
            {
                staffPersons = pageCache[StaffPersonsListKey] as ArrayList;
                if (staffPersons == null)
                {
                    staffPersons = new ArrayList();
                    pageCache[StaffPersonsListKey] = staffPersons;
                    pageCachePolicy.Cache(PageCacheKey, pageCache);
                }
                return staffPersons;
            }
            set
            {
                pageCache[StaffPersonsListKey] = value;
                pageCachePolicy.Cache(PageCacheKey, pageCache);
            }
        }

        /// <summary>
        /// Gets/Sets the list of (external) StaffPerson objects that are currently instantiated
        /// (generated during this use of the wizard)
        /// </summary>
        private ArrayList ExternalStaff
        {
            get
            {
                externalStaff = pageCache[ExternalStaffKey] as ArrayList;
                if (externalStaff == null)
                {
                    externalStaff = new ArrayList();
                    pageCache[ExternalStaffKey] = externalStaff;
                    pageCachePolicy.Cache(PageCacheKey, pageCache);
                }
                return externalStaff;
            }
            set
            {
                pageCache[ExternalStaffKey] = value;
                pageCachePolicy.Cache(PageCacheKey, pageCache);
            }
        }

        /// <summary>
        /// Indicates whether staffing updates must persist in REX
        /// </summary>
        private bool MustUpdateREX
        {
            get
            {
                // we can't add a check on whether the protocol is locked because the users
                // can change contact person designation on locked protocols and these changes
                // need to make it to REX
                if (protocolProcessId == 0)
                {
                    return true;
                }

                return (protocolProcessId > 0) &&
                    (ProtocolProcess.Type == Constants.ProtocolProcessType.InitialReview
                        || ProtocolProcess.Type == Constants.AnimalProtocolProcessType.InitialReview)
                            && ((ProtocolProcess.Status == Constants.ProtocolProcessStatus.Submitted) ||
                                (!ProtocolProcess.Locked &&
                                    (ProtocolProcess.Status == Constants.ProtocolProcessStatus.Pending)));
            }
        }

        #endregion

        /// <summary>
        /// Get the valid list of degrees (rows of id/name pairs).
        /// This maintains the relationship between degrees and their corresponding ids for binding
        /// to the degree dropdownlist
        /// </summary>
        private DataTable Degrees
        {
            get
            {
                DataTable degrees = pageCache[DegreesKey] as DataTable;
                if (degrees == null)
                {
                    degrees = Person.GetDegreeTypes(DataAccess.ConnectionString);
                    pageCache[DegreesKey] = degrees;
                    pageCachePolicy.Cache(PageCacheKey, pageCache);
                }
                return degrees;
            }
        }

        /// <summary>
        /// Gets an arraylist of US States refCodes to be bound to the States dropdownlist
        /// </summary>
        private ArrayList States
        {
            get
            {
                states = pageCache[StatesKey] as ArrayList;
                if (states == null)
                {
                    RefCodes refs = (RefCodes) applicationCachePolicy.GetCachedObject(RefCodes.CacheKey);
                    states = refs.GetRefCodes(Constants.States.Domain);
                    pageCache[StatesKey] = states;
                    pageCachePolicy.Cache(PageCacheKey, pageCache);
                }
                return states;
            }
        }

        #region Web Form Designer generated code

        /// <summary>
        /// Initializes the page and sets up the caching policies
        /// </summary>
        /// <param name="e">arguments from the event</param>
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);

            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
            applicationCachePolicy =
                (Policy.ICachePolicy) Application[Policy.Names.ApplicationCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.header.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.humansSubModuleNavigation.Navigate += new PHSRAG.Insight21.InsightWebControls.HumansSubModuleNavigation.NavigateEventHandler(this.OnNavigate);
            this.animalsSubModuleNavigation.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.breadCrumb.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnBreadCrumbNavigate);
            this.addCancel.Click += new ImageClickEventHandler(OnCancelAndSaveInternal);
            this.addNext.Click += new ImageClickEventHandler(OnAddNext);
            this.moreCancel.Click += new ImageClickEventHandler(OnCancelAndSave);
            this.moreNext.Click += new ImageClickEventHandler(OnMoreNext);
            this.formCancel.Click += new ImageClickEventHandler(OnCancelAndSave);
            this.formSave.Click += new ImageClickEventHandler(OnFormNext);
            this.Load += new System.EventHandler(this.OnPageLoad);
        }

        #endregion

        /// <summary>
        /// Displays an error message on the screen to the user with the exception, and all
        /// inner exception messages.
        /// </summary>
        /// <param name="ex">The exception to report on</param>
        private void DisplayExceptionReport(Exception ex)
        {
            annunciator.Title = AnnunciatorTitle;
            annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);
        }

        /// <summary>
        /// Sets up the breadcrumb trail; Pulls data out of the cache from under the incoming data key and
        /// stores it under the local page cache (hashtable); Sets the visibility of the different panels
        /// and assigns local variables; Binds the dropdownlists to their respective sources
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnPageLoad(object sender, EventArgs e)
        {
            try
            {
                breadCrumb.Add(
                    "Staff & Access",
                    Settings.GetKeyValue("SubModuleNavigation.Humans.AddExternalStaff",
                        "AddExternal.aspx"),
                    Settings.GetKeyValue("BreadCrumb.DetailPageLevel", 2));

                pageCache = pageCachePolicy.GetCachedObject(PageCacheKey) as Hashtable;


                if (!IsPostBack)
                {
                    if (pageCache == null)
                    {
                        pageCache = new Hashtable();
                    }

                    /* Get id coming from the originating page and clean the cache of all incoming data */
                    Hashtable incomingPageHash =
                        cachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;

                    if (incomingPageHash != null)
                    {
                        cachePolicy.UnCache(Keys.IncomingDataKey);
                        protocolId = Convert.ToInt32(incomingPageHash[Keys.ProtocolIdKey]);
                        protocolProcessId = Convert.ToInt32(incomingPageHash[Keys.ProtocolProcessIdKey]);
                        if (incomingPageHash.ContainsKey(Keys.ShowAsPopUp))
                        {
                            showAsPopUp = Convert.ToBoolean(incomingPageHash[Keys.ShowAsPopUp]);
                        }

                        StaffPersons = (ArrayList) incomingPageHash[Keys.ProtocolInternalStaffKey];
                        ExternalStaff = (ArrayList) incomingPageHash[Keys.ProtocolExternalStaffKey];
                        cachePolicy.UnCache(Keys.IncomingDataKey);

                        pageCache[Keys.ProtocolAccessKey] = incomingPageHash[Keys.ProtocolAccessKey];
                    }

                    pageCache[Keys.ProtocolIdKey] = protocolId;
                    pageCache[Keys.ProtocolProcessIdKey] = protocolProcessId;
                    pageCache[Keys.ShowAsPopUp] = showAsPopUp;
                    pageCache[ProcessKey] =
                        cachePolicy.GetCachedObject(ProtocolProcess.ProtocolProcessKey);
                    pageCachePolicy.Cache(PageCacheKey, pageCache);

                    state.DataSource = States;
                    state.DataTextField = RefCodeMeaningColumn;
                    state.DataValueField = RefCodeCodeColumn;
                    state.DataBind();

                    degree.DataSource = Degrees;
                    degree.DataTextField = DegreesNameColumn;
                    degree.DataValueField = DegreeIDColumn;
                    degree.DataBind();

                    addExternalQuestion.Visible = true;
                    addMoreQuestion.Visible = addExternalPerson.Visible = false;
                }

                else
                {
                    protocolId = (int) pageCache[Keys.ProtocolIdKey];
                    protocolProcessId = (int) pageCache[Keys.ProtocolProcessIdKey];
                    showAsPopUp = (bool) pageCache[Keys.ShowAsPopUp];
                }
                //if page is being shown as popup, then hide the header section
                headerSection.Visible = !showAsPopUp;
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
            finally
            {
                protocolDetailHeader.ProtocolID = protocolId;
                SetupPageForModuleType();
                //Set the humansubmodule Navigation links
                //humansSubModuleNavigation.ProtocolProcess=ProtocolProcess;
                //humansSubModuleNavigation.Protocol=Protocol;
            }
        }

        /// <summary>
        /// Stores the data relevant to the destination page in a hashtable and caches it under the 
        /// IncomingData key
        /// </summary>
        private void CacheOutgoingData(bool showTargetAsPopUp)
        {
            Hashtable outgoingData = new Hashtable();
            outgoingData.Add(Keys.ProtocolIdKey, protocolId);
            outgoingData.Add(Keys.ProtocolAccessKey, pageCache[Keys.ProtocolAccessKey]);
            outgoingData.Add(Keys.ProtocolProcessIdKey, protocolProcessId);
            outgoingData.Add(Keys.ProtocolReloadStaffKey, true);
            outgoingData.Add(Keys.ShowAsPopUp, showTargetAsPopUp);
            pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
        }

        /// <summary>
        /// Instantiates a StaffPerson based on the "form" filled out and adds the StaffPerson object
        /// to the arrayList of staffpersons being maintained
        /// </summary>
        private void GenerateNewStaffPerson()
        {
            int permissionLevel = Protocol.EditPermission;
            StaffPerson staff = new StaffPerson(cachePolicy, permissionLevel);
            staff.ProtocolId = protocolId;
            staff.ModuleType = Protocol.ModuleType;

            Person person = staff.Person;
            person.LastName = lastName.Text;
            person.FirstName = firstName.Text;
            person.MiddleName = middleName.Text;
            person.AdmPersonType = (int) Person.PersonType.External;
            person.OrganizationName = institution.Text;
            person.Department = department.Text;
            person.PhoneArea = telephone.AreaCode;
            person.PhoneNumber = String.Format("{0}-{1}", telephone.Exchange, telephone.Phone);
            person.Email = email.Email;
            person.DegreeId = Convert.ToInt32(degree.SelectedValue);
            person.Title = institutionTitle.Text;
            person.FaxArea = fax.AreaCode;
            person.FaxNumber = (fax.Phone == string.Empty) ? string.Empty :
                                                                              String.Format("{0}-{1}", fax.Exchange, fax.Phone);

            Address address = person.Address;
            address.Address1 = address1.Text;
            address.Address2 = address2.Text;
            address.City = city.Text;
            address.Zip = zip.Text;
            address.StateCode = state.SelectedValue;

            /* Add the person and use the property to re-cache it */
            ExternalStaff.Add(staff);
            ExternalStaff = ExternalStaff;
        }

        /// <summary>
        /// Handle the event fired by clicking next on the page (when the page displays the question
        /// "Do you need to add any people that do not belong to a Partners Institution that you did not 
        /// find in the search results?")
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments to the event</param>
        private void OnAddNext(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (addExternalAnswer.SelectedValue.Equals("Yes"))
                {
                    addExternalQuestion.Visible = addMoreQuestion.Visible = false;
                    addExternalPerson.Visible = true;
                }
                else
                {
                    ReturnToStaffPage();
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handle the event fired by clicking next on the page (when the page displays the question
        /// "Do you need to staff another external person to the protocol?")
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments to the event</param>
        private void OnMoreNext(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (addMoreAnswer.SelectedValue.Equals("Yes"))
                {
                    addExternalQuestion.Visible = addMoreQuestion.Visible = false;
                    addExternalPerson.Visible = true;
                    ResetControls();
                }
                else
                {
                    ReturnToStaffPage();
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Make necessary changes to page for use by Animals or Humans
        /// </summary>
        protected void SetupPageForModuleType()
        {
            if (Protocol.ModuleType == Constants.ModuleType.Animals)
            {
                animalsSubModuleNavigation.Visible = true;
                humansSubModuleNavigation.Visible = false;
                animalsSubModuleNavigation.ProtocolProcess = ProtocolProcess;
                animalsSubModuleNavigation.Protocol = Protocol;
                animalsSubModuleNavigation.SelectedLink = "Staff & Access";
            }
            else
            {
                humansSubModuleNavigation.Visible = true;
                animalsSubModuleNavigation.Visible = false;
                humansSubModuleNavigation.ProtocolProcess = ProtocolProcess;
                humansSubModuleNavigation.Protocol = Protocol;
                animalsSubModuleNavigation.SelectedLink = "Staff & Access";
            }
        }

        /// <summary>
        /// Performs functions necessary when the user clicks "Next" (or continue, etc.) including:
        /// 1. Saves Changes (this includes changes made by the user on the previous page, AddStaff)
        /// 2. Puts data in the cache potentially necessary for destination pages
        /// 3. Redirects the user to the destination page
        /// </summary>
        private void ReturnToStaffPage()
        {
            PersistChanges();
            CacheOutgoingData(showAsPopUp);
            Response.Redirect(Settings.GetKeyValue("SubModuleNavigation.Humans.StaffAndAccessURL",
                "StaffAndAccess.aspx"));
        }

        /// <summary>
        /// Handle the event fired by clicking next after filling out the form by caching the person data 
        /// and showing the relevant controls (or hiding the irrelevant ones)
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments to the event</param>
        private void OnFormNext(object sender, ImageClickEventArgs e)
        {
            try
            {
                //The script generated by BaseValidator for Validation Controls has a javascript block that uses document.all('controlid')
                //which is non-complaint JS code used by MS. Hence for all browsers, server side validation is done using Page.ValidateAttachment
                if (Page.IsValid)
                {
                    GenerateNewStaffPerson();
                    addExternalQuestion.Visible = addExternalPerson.Visible = false;
                    addMoreQuestion.Visible = true;
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Persists the changes the user has made to the database
        /// </summary>
        private void PersistChanges()
        {
            if (postbackGuard.IsValid)
            {
                try
                {
                    PersistInternalStaff();
                    PersistExternalStaff();
                    if (protocolProcessId > 0)
                    {
                        ProtocolProcess.Save(DataAccess.ConnectionString);
                    }
                    else
                    {
                        Protocol.Save(DataAccess.ConnectionString);
                    }

                    if (MustUpdateREX)
                    {
                        if (protocolProcessId > 0)
                        {
                            ProtocolProcess.Validated = false;
                            ProtocolProcess.UpdateStaffInREX(DataAccess.ConnectionString,
                                DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey), Protocol);
                        }
                        else
                        {
                            Protocol.UpdateStaffInREX(DataAccess.ConnectionString,
                                DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey));
                        }
                    }
                }
                catch (Exception ex)
                {
                    ExceptionReport.WriteToEventLog(
                        "AddExternal.PersistChanges", ex, true, ExceptionReport.ReportType.Error);
                    annunciator.Message = "The changes you made failed to save";
                }
            }
        }

        /// <summary>
        /// Iterates over the ArrayList of StaffPerson objects and persists them; since these people are
        /// internal (or have previously been staffed), they already have a Person object associated with 
        /// them that originated from the database so a new Person object need not be persisted (merely 
        /// the relationship -- the StaffPerson object)
        /// </summary>
        private void PersistInternalStaff()
        {
            try
            {
                int permissionLevel = Protocol.EditPermission;
                for (int i = 0; i < StaffPersons.Count; ++i)
                {
                    StaffPerson staffPerson = new StaffPerson(cachePolicy, permissionLevel);
                    staffPerson.Person.Load(DataAccess.ConnectionString,
                        (int) ((Pair) StaffPersons[i]).First);
                    staffPerson.OrganizationId = (int) ((Pair) StaffPersons[i]).Second;
                    staffPerson.RoleId = 0;
                    staffPerson.ModuleType = Protocol.ModuleType;

                    if (protocolProcessId > 0)
                    {
                        ProtocolProcess.Validated = false;
                        ProtocolProcess.AddStudyStaff(staffPerson);
                    }
                    else
                    {
                        Protocol.AddStudyStaff(staffPerson);
                    }
                }
                Protocol.Save(DataAccess.ConnectionString);
                /* Remove StaffPersons b/c they've all been persisted */
                StaffPersons = null;

                //Staff added by a process will get displayed for all the other processes and the protocol itself(trackit - 8495)
                //If the Protocol's studystafflist is not reloaded, then these changes will not appear
                Protocol.StudyStaffList = null;
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(new Exception("Your changes failed to save", ex));
            }
        }

        /// <summary>
        /// Iterates over the ArrayList of StaffPerson objects and persists them; since these people are
        /// external and not previously staffed, the Person object associated with them is not persistent
        /// in the database, so we need to persist the Person information as well
        /// </summary>
        private void PersistExternalStaff()
        {
            try
            {
                if (protocolProcessId > 0)
                {
                    for (int i = 0, count = ExternalStaff.Count; i < count; ++i)
                    {
                        ProtocolProcess.AddStudyStaff((StaffPerson) ExternalStaff[i]);
                    }
                }

                else
                {
                    for (int i = 0, count = ExternalStaff.Count; i < count; ++i)
                    {
                        Protocol.AddStudyStaff((StaffPerson) ExternalStaff[i]);
                    }
                }

                Protocol.Save(DataAccess.ConnectionString);
                /* Remove StaffPersons b/c they've all been persisted */
                ExternalStaff = null;

                //Staff added by a process will get displayed for all the other processes and the protocol itself(trackit - 8495)
                //If the Protocol's studystafflist is not reloaded, then these changes will not appear
                Protocol.StudyStaffList = null;
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(new Exception("Your changes failed to save", ex));
            }
        }

        /// <summary>
        /// Resets all input-type controls on the page to their default values
        /// </summary>
        private void ResetControls()
        {
            lastName.Text = firstName.Text = middleName.Text = address1.Text = address2.Text = city.Text =
                institution.Text = department.Text = institutionTitle.Text = zip.Text = string.Empty;

            state.DataSource = States;
            state.DataTextField = RefCodeMeaningColumn;
            state.DataValueField = RefCodeCodeColumn;
            state.DataBind();

            degree.DataSource = Degrees;
            degree.DataTextField = DegreesNameColumn;
            degree.DataValueField = DegreeIDColumn;
            degree.DataBind();

            telephone.Reset();
            email.Reset();
            fax.Reset();
        }

        /// <summary>
        /// Resets the subnavigation selected link before the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnBreadCrumbNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                humansSubModuleNavigation.Reset();
                animalsSubModuleNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link before the header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNavigate(object sender, CommandEventArgs e)
        {
            try
            {
                humansSubModuleNavigation.Reset();
                animalsSubModuleNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handles the cancel button click event by persisting staff updates,
        /// except those which took place on the current "page" (if the current page
        /// is the form to staff a new external person), and redirecting to the 
        /// StaffAndAccess page
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnCancelAndSave(object sender, ImageClickEventArgs e)
        {
            try
            {
                ReturnToStaffPage();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handles the cancel button click event by persisting staff updates,
        /// and redirecting to the StaffAndAccess page
        /// 
        /// Note: from this path, only internal people will have been staffed so
        /// a call to PersistExternalChanges must not be made.
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnCancelAndSaveInternal(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (postbackGuard.IsValid)
                {
                    try
                    {
                        PersistInternalStaff();
                        if (MustUpdateREX)
                        {
                            if (protocolProcessId > 0)
                            {
                                ProtocolProcess.Validated = false;
                                ProtocolProcess.UpdateStaffInREX(DataAccess.ConnectionString,
                                    DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey),
                                    Protocol);
                            }
                            else
                            {
                                Protocol.UpdateStaffInREX(DataAccess.ConnectionString,
                                    DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey));
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("The changes failed to save", ex);
                    }
                }

                CacheOutgoingData(showAsPopUp);
                Response.Redirect(Settings.GetKeyValue("SubModuleNavigation.Humans.StaffAndAccessURL",
                    "StaffAndAccess.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Constructs and caches a hashtable of data for use by the page to which nagivation leads
        /// </summary>
        private void OnNavigate()
        {
            try
            {
                CacheOutgoingData(false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }
    }
}